/*
	Author: Christian Wico - cwico@tractionondemand.com
	Description: Controller extension for custom forecasting too.
*/
public class trac_ForecastControllerExt {
	
	public List<Forecast_Month__c> byMonthList {get;set;}
	public Map<string, List<FiscalMonth>> forecastMap {get; set;} 
	public List<string> forecastList {get; set;}
	
	private final Forecast__c forecast;
	public Forecast__c forecastNFY {get; set;} // next fiscal year forecast if available
    
    
    integer previousYear, currentYear, nextYear, finalYear, columns = 0;
    
    public List<FiscalMonth> bookings {get {return forecastMap.get('Booking');} set; } 
    public List<FiscalMonth> passengers {get {return forecastMap.get('Passenger');} set; }
    public List<FiscalMonth> marketing {get {return forecastMap.get('Marketing');} set; }
    
    public Map<string, List<FiscalMonth>> getForecastMap {get {return forecastMap;} set{}}
    
    public RecordType bookingRType {get;set;}
    public RecordType marketingRType {get;set;}
    public RecordType passengerRType {get;set;}
        
    
    public string trStart {get{return '<tr>';} set{}}
	public string trEnd {get{return '</tr>';} set{}}
	public string tdStart {get{return '<td>';} set{}}
	public string tdEnd {get{return '</td>';} set{}}
	public string thStart {get{return '<th>';} set{}}
	public string thEnd {get{return '</th>';} set{}}
	public integer columnCount {get{return columns;} set{}}
	
    
    public trac_ForecastControllerExt(ApexPages.StandardController stdController) {
        
        bookingRType = [SELECT Id, Name FROM RecordType WHERE Name = 'Booking Revenue Fcst' LIMIT 1];
        marketingRType = [SELECT Id, Name FROM RecordType WHERE Name = 'Marketing Spend Fcst' LIMIT 1];
        passengerRType = [SELECT Id, Name FROM RecordType WHERE Name = 'Passenger Count Fcst' LIMIT 1];
        
        forecastMap = new Map<string, List<FiscalMonth>> {
			'Booking' => new List<FiscalMonth>(), 
			'Passenger' => new List<FiscalMonth>(), 
			'Marketing'=> new List<FiscalMonth>()
		}; 
        forecastList = new List<string> {'Booking', 'Passenger', 'Marketing'};
        
        this.forecast = [SELECT Id, Name, Year__c, Account__c, Budget_Booking_Revenue__c, Budget_Marketing_Spend__c, Budget_Passenger_Count__c 
        					FROM Forecast__c 
        					WHERE Id=:stdController.getRecord().Id 
        				LIMIT 1];
        
        //System.debug(forecast);
        currentYear = integer.valueOf(forecast.Year__c);
        finalYear = currentYear + 2;
        
        List<Forecast__c> tmp = [SELECT Id, Name, Year__c, Account__c, Budget_Booking_Revenue__c, Budget_Marketing_Spend__c, Budget_Passenger_Count__c 
        							FROM Forecast__c 
        							WHERE Account__c = :forecast.Account__c AND Year__c=:string.valueOf(finalYear)];
    	//System.debug(tmp);
    	
    	if (tmp.size() > 0) {
    		forecastNFY = tmp.get(0);
    		//System.debug(forecastNFY);
    	}
    	else {
    		forecastNFY = new Forecast__c();
    		forecastNFY.Budget_Booking_Revenue__c = 0;
    		forecastNFY.Budget_Marketing_Spend__c = 0;
    		forecastNFY.Budget_Passenger_Count__c = 0;
    	}
    	
                
        
        // every november
        DateTime startDate = DateTime.newInstance(currentYear, 11, 1, 7, 0, 0);
        DateTime endDate = startDate.addMonths(11);
        DateTime startDate6MStart = startDate.addMonths(-6);
        
        DateTime startDateNY = DateTime.newInstance(finalYear, 5, 1, 7, 0, 0);
        DateTime endDateNY = DateTime.newInstance(finalYear, 10, 1, 10, 0, 0); 
        
        //System.debug(endDateNY);
       
        
        // get existing data
        byMonthList = [
        		SELECT Id, Name, Forecast__c, RecordTypeId, 
        			Month__c, Type__c, Year__c, 
        			Forecast_Count__c, Actual_Count__c, 
        			Forecast_Revenue__c, Actual_Revenue__c,
        			Forecast_Spend__c, Actual_Spend__c,
        			Comment__c  
        		FROM Forecast_Month__c 
        		WHERE 
        			Forecast__r.Account__c = :forecast.Account__c
        			/*
        			AND
        			Forecast__c = :forecast.Id
        			*/
        			AND (
        				Year__c = :string.valueOf(currentYear-1) OR 
        				Year__c = :string.valueOf(currentYear) OR 
        				(Year__c = :string.valueOf(currentYear+1) AND Forecast__c = :forecast.Id) OR 
        				(Year__c = :string.valueOf(currentYear+2) AND Forecast__c = :forecast.Id)
        			)
        			
        		ORDER BY Type__c, Year__c  
        ];
        
       	//System.debug('By Month List: ' + byMonthList);
        //System.debug('By Month List Size: ' + byMonthList.size());
        
        // build fiscal map
        DateTime d = startDate6MStart;
        //integer c = 0;
        
        while (d <= endDateNY) {
        	//System.debug(d);				

			boolean isCurrentYear = d >= startDate && d <= endDate; 
			boolean isNextYear = d >= startDateNY && d <= endDateNY; 
	        boolean isPreviousYear = d < startDate;

	        boolean editable = (isCurrentYear || isNextYear); 
	        boolean validDate =  isPreviousYear || editable; 
				
			//System.debug('validDate: ' + validDate);	
			if (validDate) {
					
				// each forecast type
				for(string forecastType: forecastMap.keySet()) {
		       		FiscalMonth fm = new FiscalMonth();
		       		fm.Type = forecastType;
		       		fm.MonthNo = d.month();
		       		fm.MonthName = d.format('MMMM');
		       		fm.MonthShort = d.format('MMM');
		       		fm.Year = d.year();
		       		fm.Editable = editable;
		       		fm.YearType = (isCurrentYear)? 'current':(isPreviousYear)? 'previous':'next';
					fm.Index = forecastMap.get(forecastType).size();

					fm.FM = findForecastMonth(fm.MonthName, fm.Year, fm.Type);
					
					// create new if not found
					if (fm.FM == null) {
						// new
						Forecast_Month__c newFM = new Forecast_Month__c();
						newFM.Month__c = fm.MonthName;
						newFM.Year__c = string.valueOf(fm.Year);
						newFM.Type__c = forecastType;
						newFM.Forecast__c = forecast.Id;
						newFM.RecordTypeId = getRecordTypeFor(forecastType).Id;
						
						fm.FM = newFM;
						
						
						if (fm.Editable) {
							//System.debug(newFM);
							fm.IsNew = true;
							//c++;
						}
						else {
							// placeholder
							fm.IsNew = false;
							fm.IsPlaceholder = true;
						}
						
					}
					else {
						fm.IsUpdate = true;
					}
					
					// get prior year/month forecast
					fm.PriorYFM = findForecastMonth(fm.MonthName, fm.Year-1, fm.Type);
					
					// create dummy record
					if (fm.PriorYFM == null) {
						Forecast_Month__c newYFM = new Forecast_Month__c();
						newYFM.Month__c = fm.MonthName;
						newYFM.Year__c = string.valueOf(fm.Year-1);
						newYFM.RecordTypeId = getRecordTypeFor(forecastType).Id;
						
						fm.PriorYFM = newYFM;
					}
					
					
					// add default values to actuals and forecasts
					if (fm.FM.Forecast_Revenue__c == null) fm.FM.Forecast_Revenue__c = 0;
					if (fm.FM.Actual_Revenue__c == null) fm.FM.Actual_Revenue__c = 0;
					
					if (fm.FM.Forecast_Spend__c == null) fm.FM.Forecast_Spend__c = 0;
					if (fm.FM.Actual_Spend__c == null) fm.FM.Actual_Spend__c = 0;
					
					if (fm.FM.Forecast_Count__c == null) fm.FM.Forecast_Count__c = 0;
					if (fm.FM.Actual_Count__c == null) fm.FM.Actual_Count__c = 0;
					
					
					if (fm.PriorYFM.Forecast_Revenue__c == null) fm.PriorYFM.Forecast_Revenue__c = 0;
					if (fm.PriorYFM.Actual_Revenue__c == null) fm.PriorYFM.Actual_Revenue__c = 0;
					
					if (fm.PriorYFM.Forecast_Spend__c == null) fm.PriorYFM.Forecast_Spend__c = 0;
					if (fm.PriorYFM.Actual_Spend__c == null) fm.PriorYFM.Actual_Spend__c = 0;
					
					if (fm.PriorYFM.Forecast_Count__c == null) fm.PriorYFM.Forecast_Count__c = 0;
					if (fm.PriorYFM.Actual_Count__c == null) fm.PriorYFM.Actual_Count__c = 0;					
					
					
		        	// insert forecast map to list	
		       		forecastMap.get(forecastType).add(fm);

		       	}
		       	//columns++;
			}
        
        	d = d.addMonths(1);	
        	
        }
        
      	//System.debug('New Counter: ' + c);
      	
    }

	public RecordType getRecordTypeFor(string groupName) {
		if (groupName == 'Booking') {
    		return bookingRType;
    	}
		else if (groupName == 'Passenger') {
			return passengerRType;
		}
		
		// Marketing
		return marketingRType;
	}
	
	public string getGroupName(object name) {
		return string.valueOf(name).toLowerCase();
	}

	public void doSave() {
		//System.debug(bookings);
		List<Forecast_Month__c> insertList = new List<Forecast_Month__c>(); 
		List<Forecast_Month__c> updateList = new List<Forecast_Month__c>();
		
		for(string t: forecastMap.keySet()) {
			for(FiscalMonth fm: forecastMap.get(t)) {
				if (fm.Editable) {
					if (fm.IsNew == true) {
						insertList.add(fm.FM);
						fm.IsNew = false;
						fm.IsUpdate = true;  
					}
					
					else if (fm.IsUpdate == true) { // Null means readonly records
						updateList.add(fm.FM);
					}
					
				}
				else {
					if (fm.IsPlaceholder != true) {
						updateList.add(fm.FM);
					}
				}
			}
			
		}
		
		if (insertList.size() > 0) insert insertList ;
		if (updateList.size() > 0) update updateList ;
		
		
	}
	
	public Forecast_Month__c findForecastMonth(string monthName, integer year, string typeName) {
		for (Forecast_Month__c fm: byMonthList) {
			if (fm.Month__c == monthName && fm.Year__c == string.valueOf(year) && fm.Type__c == typeName) {
				// existing
				return fm;
			}
		}
		return null;
	}
	
	// helper class
	private class FiscalMonth {
		public string ID {
			get {
				//return Type + '-' + YearType + '-' + MonthShort + '-' + Year;  
				return Type + '-' + MonthShort + '-' + Year;
			}
		}
		
		public string Type {get;set;}
		public string MonthShort {get;set;}
		public string MonthName {get;set;}
		public integer MonthNo {get;set;}
		public integer Year {get;set;}
		public string YearType {get;set;}
		public boolean Editable {get;set;}
		public string Comments {get;set;}
		public integer Index {get;set;}	
		public boolean IsNew {get;set;}
		public boolean IsPlaceholder {get;set;}
		public boolean IsUpdate {get;set;}
		public boolean Save {get;set;}
		public Forecast_Month__c FM {get; set;}
		public Forecast_Month__c PriorYFM {get; set;}
		public Forecast_Month__c AddYFM {get; set;}
	}
	
}